package com.linchong.concurrency.chapter10.v1;

import java.util.ArrayList;
import java.util.Collection;
import java.util.Collections;
import java.util.Optional;

/**
 * @Author:linchong
 * @CreateTime:2020-07-28 08:58
 * @Description:
 */
public class BooleanLock implements Lock {

	/**
	 * the initValue is true indicated the lock have be get
	 * otherwise indicated the lock is free,other thread can get this
	 */
	private boolean initValue;

	/**
	 * 当前线程的标识，用来判断线程解锁的执行权限
	 */
	private Thread currentThread;

	private final Collection<Thread> blockedThreadCollection = new ArrayList<>();

	public BooleanLock() {
		this.initValue = false;
	}

	/**
	 * 加锁
	 * 当前实例获取锁，锁住，放到阻塞队列中
	 *
	 * @throws InterruptedException
	 */
	@Override
	public synchronized void lock() throws InterruptedException {
		//获取锁，被其他线程的阻塞，加入阻塞集合，锁住
		while (initValue) {
			blockedThreadCollection.add(Thread.currentThread());
			this.wait();
		}
		//获取锁
		blockedThreadCollection.remove(Thread.currentThread());
		//释放锁
		initValue = true;
		this.currentThread = Thread.currentThread();
	}

	/**
	 * 超时释放锁
	 *
	 * @param mills
	 * @throws InterruptedException
	 */
	@Override
	public synchronized void lock(long mills) throws InterruptedException, TimeOutException {
		if(mills < 0){
			lock();
		}
		long hasRemaining = mills;
		long endTime = System.currentTimeMillis() + mills;
		while (initValue){
			//等待时，其他线程抢到锁，当前线程继续等待，判断那她是否过期，没有过期继续等待，过期了就移除，
			if(hasRemaining<=0){
				throw new TimeOutException("time out");
			}
			blockedThreadCollection.add(Thread.currentThread());
			this.wait(mills);
			hasRemaining = endTime - System.currentTimeMillis();
		}
		this.initValue = true;
		this.currentThread = Thread.currentThread();
	}

	/**
	 * 释放锁
	 * 获取锁
	 */
	@Override
	public synchronized void unlock() {
		if(Thread.currentThread()==currentThread){
			//释放锁，
			this.initValue = false;
			Optional.of(Thread.currentThread().getName() + " release the lock monitor.")
					.ifPresent(System.out::println);
			this.notifyAll();
		}

	}

	/**
	 * 获取阻塞的锁
	 *
	 * @return
	 */
	@Override
	public Collection<Thread> getBlockedThread() {
		//只读，不可修改，保证安全
		return Collections.unmodifiableCollection(blockedThreadCollection);
	}

	/**
	 * 获取阻塞锁的数量
	 *
	 * @return
	 */
	@Override
	public int getBlockedSize() {
		return blockedThreadCollection.size();
	}
}
